1 /* 2 * Collie - An asynchronous event-driven network framework using Dlang development 3 * 4 * Copyright (C) 2015-2017 Shanghai Putao Technology Co., Ltd 5 * 6 * Developer: putao's Dlang team 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 module collie.codec.http.session.httpdownstreamsession; 12 13 import std.exception; 14 15 import collie.codec.http.session.httpsession; 16 import collie.codec.http.headers; 17 import collie.codec.http.codec.wsframe; 18 import collie.codec.http.httpmessage; 19 import collie.codec.http.httptansaction; 20 import collie.codec.http.codec.httpcodec; 21 import std.base64; 22 import std.digest.sha; 23 import collie.codec.http.codec.websocketcodec; 24 25 final class HTTPDownstreamSession : HTTPSession 26 { 27 this(HTTPSessionController controller,HTTPCodec codec, SessionDown down) 28 { 29 super(controller,codec,down); 30 } 31 32 protected: 33 override void setupOnHeadersComplete(ref HTTPTransaction txn, 34 HTTPMessage msg) 35 { 36 auto handle = _controller.getRequestHandler(txn,msg); 37 if(handle is null) 38 { 39 try{ 40 enum string _404 = "<h1>Not Found!</h1><p>the http RequestHandle is null!</p>"; 41 import collie.codec.http.headers; 42 import std.typecons; 43 import std.conv; 44 scope HTTPMessage rmsg = new HTTPMessage(); 45 rmsg.statusCode = 404; 46 rmsg.statusMessage = HTTPMessage.statusText(404); 47 rmsg.getHeaders.add(HTTPHeaderCode.CONNECTION,"close"); 48 rmsg.getHeaders.add(HTTPHeaderCode.CONTENT_LENGTH,to!string(_404.length)); 49 sendHeaders(txn,rmsg,false); 50 sendBody(txn,cast(ubyte[])_404,true); 51 txn = null; 52 } catch (Exception e){ 53 import collie.utils.exception; 54 showException(e); 55 } 56 } else { 57 txn.handler(handle); 58 txn.onIngressHeadersComplete(msg); 59 } 60 } 61 62 override void setupProtocolUpgrade(ref HTTPTransaction txn,CodecProtocol protocol,string protocolString,HTTPMessage msg) { 63 void doErro(){ 64 scope HTTPMessage rmsg = new HTTPMessage(); 65 rmsg.statusCode = 400; 66 rmsg.statusMessage = HTTPMessage.statusText(400); 67 rmsg.getHeaders.add(HTTPHeaderCode.CONNECTION,"close"); 68 sendHeaders(txn,rmsg,true); 69 } 70 auto handle = _controller.getRequestHandler(txn,msg); 71 if(handle is null){ 72 collectException( doErro()); 73 return; 74 } 75 txn.handler(handle); 76 if(protocol == CodecProtocol.init || !txn.onUpgtade(protocol, msg)) 77 { 78 collectException( doErro()); 79 return; 80 } 81 bool rv = true; 82 switch(protocol){ 83 case CodecProtocol.WEBSOCKET : 84 rv = doUpgradeWebSocket(txn,msg); 85 break; 86 default : 87 rv = false; 88 break; 89 } 90 if(!rv) 91 doErro(); 92 } 93 94 bool doUpgradeWebSocket(ref HTTPTransaction txn,HTTPMessage msg) 95 { 96 string key = msg.getHeaders.getSingleOrEmpty(HTTPHeaderCode.SEC_WEBSOCKET_KEY); 97 string ver = msg.getHeaders.getSingleOrEmpty(HTTPHeaderCode.SEC_WEBSOCKET_VERSION); 98 if(ver != "13") 99 return false; 100 auto accept = cast(string) Base64.encode(sha1Of(key ~ WebSocketGuid)); 101 102 scope HTTPMessage rmsg = new HTTPMessage(); 103 rmsg.statusCode = 101; 104 rmsg.statusMessage = HTTPMessage.statusText(101); 105 rmsg.getHeaders.add(HTTPHeaderCode.CONNECTION,"keep-alive"); 106 rmsg.getHeaders.add(HTTPHeaderCode.SEC_WEBSOCKET_ACCEPT,accept); 107 rmsg.getHeaders.add(HTTPHeaderCode.CONNECTION,"Upgrade"); 108 rmsg.getHeaders.add(HTTPHeaderCode.UPGRADE,"websocket"); 109 sendHeaders(txn,rmsg,false); 110 restCodeC(new WebsocketCodec(TransportDirection.DOWNSTREAM,txn)); 111 return true; 112 } 113 114 } 115 116